#include "exploit.h"
#include "utils.h"
#include "loose_version.h"

#include <fstream>
#include <iostream>

#include <boost/tokenizer.hpp>
#include <boost/regex.hpp>

// 用于匹配名称的正则表达式模版，其中第一个参数为level, 其二个参数是软件名称
static const char *g_match_cve_regex_fmt = "(^[\\\"]*(\\w*\\s){0,1}|/\\s?)%s(\\s|\\s.*\\s|\\/).* -";

std::list<software::exploit::Exploit> software::exploit::load_exploits(const char *cve_repo_path)
{
    std::list<Exploit> exploits;
    std::ifstream in(cve_repo_path);
    if (!in)
    {
        std::cout << "open file: "<< cve_repo_path << "failed!!!" << std::endl;
        return exploits;
    }
    typedef boost::tokenizer< boost::char_separator<char> > Tokenizer;
    boost::char_separator<char> sep(",");

    // 跳过表头
    std::string line;
    getline(in, line);

    std::vector<std::string> tokens;
    while (getline(in, line))
    {
        Tokenizer tok(line, sep);
        Exploit exploit;
        tokens.assign(tok.begin(), tok.end());

        if (tokens.size() < 7)
        {
            continue;
        }

        exploit.exploit_id          = atoll(tokens[EN_EXPLOIT_ID].c_str());
        exploit.exploit_file_path   = tokens[EN_EXPLOIT_FILE];
        exploit.exploit_description = tokens[EN_EXPLOIT_DESCRIPTION];
        exploit.exploit_date        = tokens[EN_EXPLOIT_DATE];
        exploit.exploit_author      = tokens[EN_EXPLOIT_AUTHOR];
        exploit.exploit_type        = tokens[EN_EXPLOIT_TYPE];
        exploit.exploit_platform    = tokens[EN_EXPLOIT_PLATFORM];
        exploit.exploit_cve_id      = tokens[EN_EXPLOIT_CVE_ID];

        // 从描述中提取受影响的版本列表
        exploit.exploit_versions    = software::utils::extract_versions(tokens[EN_EXPLOIT_DESCRIPTION].c_str());

        exploits.push_back(exploit);
    }
    return exploits;
}

bool software::exploit::search_exploit(const char *seftware, const char *version, const std::list<software::exploit::Exploit> &cve_list, std::list<software::exploit::Exploit> &report)
{
    std::string version_search = version;
    bool match = false;

    char software_name[256];
    bzero(software_name, sizeof(software_name));
    snprintf(software_name, sizeof (software_name), g_match_cve_regex_fmt, software::utils::soft_name(seftware).c_str());

    // 匹配软件名称是否存在问题
    //if (re2::RE2::PartialMatch(exploit.exploit_description, software_name))
    boost::regex reg(software_name, boost::regex::icase);
    for (std::list<Exploit>::const_iterator iter = cve_list.cbegin(); iter != cve_list.cend(); ++iter)
    {
        const Exploit &exploit = *iter;
        if (!software::utils::is_valid_platforms(exploit.exploit_platform.c_str()))
        {
            continue;
        }

        if (boost::regex_search(exploit.exploit_description, reg))
        {
            // 获得影响的版本，如果当前软件版本小于漏洞版本，则进行报警
            const std::list<std::string> &affected_versions = exploit.exploit_versions;
            for (std::list<std::string>::const_iterator version_iter = affected_versions.begin(); version_iter != affected_versions.end(); ++version_iter)
            {
                CLooseVersion version_l (version);
                CLooseVersion version_r ((*version_iter).c_str());
                if (version_l <= version_r)
                {
                    report.push_back(exploit);
                    match = true;
                    break;
                }
            }

        }
    }
    return match;
}
